﻿//-----------------------------------------------------------------------
// <copyright file="IEntity.cs" company="Nathan Miller">
// Copyright (c) Nathan Miller.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
//-----------------------------------------------------------------------
namespace TileTool.Scene.Entity
{
    using System;
    using TileTool.Common.Math;
    using TileTool.DataBag;
    using TileTool.Render;
    using TileTool.Scene.Collision;

    /// <summary>
    /// Interface for all entities in the editor.
    /// </summary>
    public interface IEntity
    {
        #region Events

        /// <summary>
        /// Event triggered when the entity changes.
        /// </summary>
        event EntityChanged Changed;

        #endregion

        #region Properties - General

        /// <summary>
        /// Gets or sets the name of the entity.
        /// </summary>
        string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the GUID of the entity.
        /// </summary>
        Guid Guid
        {
            get;
        }

        /// <summary>
        /// Gets the data bag for the object.
        /// 
        /// The data bag is the model of the entity and all entity data should be stored
        /// in the data bag.
        /// 
        /// For example, the entity's matrix is stored in the data bag as a IDataBagValue<Matrix2D>
        /// with a name of EntityDataBagKeys.Matrix.
        /// </summary>
        IDataBag Bag
        {
            get;
        }

        /// <summary>
        /// Gets or sets the color of the entity.
        /// </summary>
        ColorRGBA Color
        {
            get;
            set;
        }

        #endregion

        #region Properties - Position / Orientation / Size

        /// <summary>
        /// Gets if this entity can be sized.
        /// </summary>
        bool CanSize
        {
            get;
        }

        /// <summary>
        /// Gets or sets the position of the entity in world space.
        /// </summary>
        Vector2D Pos
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the matrix associated with the entity in world space.
        /// </summary>
        Matrix2D Matrix
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the matrix of the entity in parent space.
        /// </summary>
        Matrix2D ParentMatrix
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the size of the entity.
        /// 
        /// Should trigger the SizeChanged event and clamp against EntityUtility.MinSize.
        /// </summary>
        Size2D Size
        {
            get;
            set;
        }

        #endregion

        #region Properties - Object state

        /// <summary>
        /// Gets or sets if the scene the entity is currently is in. null means
        /// the entity is not in a scene.
        /// </summary>
        ISceneManager Scene
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the parent entity of this entity. Can be null.
        /// </summary>
        IEntity Parent
        {
            get;
            set;
        }

        /// <summary>
        /// Gets a read only collection which contains the children for this entity.
        /// </summary>
        IEntityCollection Children
        {
            get;
        }

        /// <summary>
        /// Gets or sets if the entity is selected.
        /// </summary>
        bool Selected
        {
            get;
            set;
        }

        /// <summary>
        /// Gets if any descendants of this entity are selected.
        /// </summary>
        bool DescendantSelected
        {
            get;
        }

        /// <summary>
        /// Gets or sets if the entity is visible and should be drawn.
        /// </summary>
        bool Visible
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets if the entity is frozen.
        /// </summary>
        bool Frozen
        {
            get;
            set;
        }

        #endregion

        #region Methods - Draw

        /// <summary>
        /// Draw the entity with the passed renderer.
        /// 
        /// When Draw() is called, the entities matrix will have been pushed on
        /// to the renderer's matrix stack. This means that all entity rendering will
        /// happen in local space.
        /// </summary>
        /// <param name="renderData">Rendering data. Always non-null.</param>
        void Draw(IRenderData renderData);

        /// <summary>
        /// Called to draw the entity if it is selected.
        /// 
        /// When DrawSelected() is called, the entities matrix will have been pushed on
        /// to the renderer's matrix stack. This means that all entity rendering will
        /// happen in local space.
        /// </summary>
        /// <param name="renderData">Rendering data. Always non-null.</param>
        void DrawSelected(IRenderData renderData);

        #endregion

        #region Methods - Collision

        /// <summary>
        /// Tests if the passed rectangle intersects or contains the rectangle
        /// of this entity.
        /// </summary>
        /// <param name="rect">Rectangle to test against.</param>
        /// <returns>Returns true if there was an intersection.</returns>
        bool Intersects(Rect2D rect);

        /// <summary>
        /// Handle collision against this entity for the provided collision
        /// request.
        /// 
        /// If the request hits an entity, should return the entity that was hit.
        /// </summary>
        /// <param name="request">Collision request.</param>
        /// <returns>Returns the entity that was hit or null if no entity was hit.</returns>
        IEntity HandleCollision(CollisionRequest request);

        #endregion

        #region Methods - Parent Child

        /// <summary>
        /// Add the passed entity as a child to this entity.
        /// </summary>
        /// <param name="entity">Entity to add.</param>
        void AddChild(IEntity entity);

        /// <summary>
        /// Remove the passed entity from this one as a child.
        /// </summary>
        /// <param name="entity">Entity to remove.</param>
        void RemoveChild(IEntity entity);

        #endregion
    }
}
